package edu.ucsc.gameAI;

import java.awt.Color;
import java.util.ArrayList;

import pacman.game.Constants.MOVE;
import pacman.game.Game;
import pacman.game.GameView;
import pacman.game.Constants.DM;
import pacman.game.Constants.GHOST;
import pacman.game.internal.Ghost;
import edu.ucsc.gameAI.Debug.MESSAGETYPE;
import edu.ucsc.gameAI.conditions.DoesNodeContainGhost;

public class FindJunction {
	
	//find all nearby junctions to pacman. Search to the specified depth of recursion
	public int findClosestJunction(Game game, int[] neighborNodes, int currentNodeIndex, int depth, int currentJunction, ArrayList<Integer> path)
	{		
		GameView gv = new GameView(game);

		int returnIndex = -1;
		
		//the array of neighbors near our currentNodeIndex
		for (int neighbor : neighborNodes)
		{
			//if the neighbor contains a ghost, ignore this path as it is unsafe
			for (GHOST ghost : GHOST.values()) {
				
				if(game.getGhostLairTime(ghost) > 0 || game.isGhostEdible(ghost))
					continue;
				
				int ghostIndex = game.getGhostCurrentNodeIndex(ghost);

				if (neighbor == ghostIndex && 
						(game.getShortestPathDistance(ghostIndex, currentJunction) < 
								game.getShortestPathDistance(game.getPacmanCurrentNodeIndex(), currentJunction)))
				{
					path.remove(path.size()-1);
					Debug.debug("Path unsafe because " + ghost + " is in the way. The list so far " + path + " ", MESSAGETYPE.ACTION);
					return -2;
				}

			}
			
			//if we've found a junction, let's explore it to see if it's safe
			if(game.isJunction(neighbor))
			{
				if(path.contains(neighbor))
					return -1;
				
				Debug.debug("Found junction " + neighbor + " the path so far is " + path, MESSAGETYPE.STATEMENT);
				if(depth > 0)
				{
					Debug.debug("Checking for safety " + neighbor, MESSAGETYPE.STATEMENT);
					path.add(neighbor);
					GameView.addPoints(game, getDotColor(depth), neighbor);
					GameView.addLines(game, Color.GREEN, currentJunction, neighbor);
					gv.repaint();
					returnIndex = findClosestJunction(
						game, 
						game.getNeighbouringNodes(neighbor, game.getNextMoveTowardsTarget(currentNodeIndex, neighbor, DM.PATH)), 
						neighbor, --depth, neighbor, path);
				}
				else
				{
					path.add(neighbor);
					GameView.addPoints(game, getDotColor(depth), neighbor);
					GameView.addLines(game, Color.GREEN, currentJunction, neighbor);
					gv.repaint();
					returnIndex = determineSafeIndex(
							game, 
							game.getNeighbouringNodes(neighbor, game.getNextMoveTowardsTarget(currentNodeIndex, neighbor, DM.PATH)), 
							neighbor, neighbor, path);
				}
			}
			
			//ptherwise keep looking to find a junction
			else if (returnIndex == -1){
				returnIndex = findClosestJunction( 
						game, 
						game.getNeighbouringNodes(neighbor, game.getNextMoveTowardsTarget(currentNodeIndex, neighbor, DM.PATH)), 
						neighbor, depth, currentJunction, path);
			}
			if(returnIndex == -2)
				return -1;

		}
		return returnIndex;	
	}
	
	//we've found a juntion, now we're going to try to find its closes junctions
	private int determineSafeIndex(Game game, int[] neighborNodes, int currentNodeIndex, int currentJunction, ArrayList<Integer> path)
	{
		boolean foundGhost = false;
		GameView gv = new GameView(game);

		//for all the neighbors found near our currentNodeIndex
		for (int neighbor : neighborNodes)
		{
			//if the neighbor contains a ghost, ignore this path as it is unsafe
			for (GHOST ghost : GHOST.values()) {
				
				if(game.getGhostLairTime(ghost) > 0 || game.isGhostEdible(ghost))
					continue;
				
				int ghostIndex = game.getGhostCurrentNodeIndex(ghost);

				if (neighbor == ghostIndex && 
						(game.getShortestPathDistance(ghostIndex, currentJunction) < 
								game.getShortestPathDistance(game.getPacmanCurrentNodeIndex(), currentJunction)))
				{
					path.remove(path.size()-1);
					Debug.debug("Path unsafe because " + ghost + " is in the way. The list so far " + path + " ", MESSAGETYPE.ACTION);
					foundGhost = true;
					break;
				}

			}
			
			if(foundGhost)
				continue;
			
			//is we made it to a junction, this path is safe so return its index
			if(game.isJunction(neighbor))
			{
				path.add(neighbor);
				Debug.debug("This junction is our new destination " + neighbor, MESSAGETYPE.STATEMENT);
				GameView.addPoints(game, Color.RED, neighbor);
				gv.repaint();
				return neighbor;
			}
			
			//ptherwise keep looking to find a junction
			else {
				return determineSafeIndex(
						game, 
						game.getNeighbouringNodes(neighbor, game.getNextMoveTowardsTarget(currentNodeIndex, neighbor, DM.PATH)), 
						neighbor, currentJunction, path);
			}

		}
		Debug.debug("Somehow made it out of the for loop in determineSafeIndex for a junction", MESSAGETYPE.STATEMENT);
		return -1;
	}
	
	//return a color based on what the current depth of the recursion is
	private Color getDotColor(int depth) {
		switch(depth) {
			case 0: return Color.ORANGE;
			case 1: return Color.YELLOW;
			case 2: return Color.GREEN;
			case 3: return Color.BLUE;
			case 4: return Color.PINK;
			case 5: return Color.DARK_GRAY;
			case 6: return Color.GRAY;
			default: return Color.BLACK;
		}
		//return Color.BLACK;
	}
	
//	private boolean pathFound = false;
//
//	public void findSafePathToIndex(Game game, int[] neighborNodes, int currentNodeIndex, int goalIndex, ArrayList<Integer> path)
//	{			
//		//the array of neighbors near our currentNodeIndex
//		for (int neighbor : neighborNodes)
//		{
//			//if the neighbor contains a ghost, ignore this path as it is unsafe
//			if (new DoesNodeContainGhost().test(game, neighbor))
//				continue;
//			
//			//if we've found the goal, return
//			if(neighbor == goalIndex)
//			{
//				pathFound = true;
//				path.add(neighbor);
//				return;
//			}
//			
//			//ptherwise keep looking to find a safe path to the goal
//			else {
//					findSafePathToIndex( 
//						game, 
//						game.getNeighbouringNodes(neighbor, game.getNextMoveTowardsTarget(currentNodeIndex, neighbor, DM.PATH)), 
//						neighbor, goalIndex, path);
//					if(pathFound)
//					{
//						path.add(neighbor);
//						break;
//					}
//			}
//
//		}
//		return;	
//	}
	


}
